<?php

/* No Shipping, Ship From, or Taxes have been implemented */
App::import('Vendor', 'gcheckout/googlecart');
App::import('Vendor', 'gcheckout/googleitem');
App::import('Vendor', 'gcheckout/googlelog');
App::import('Vendor', 'gcheckout/googlemerchantcalculations');
App::import('Vendor', 'gcheckout/googlenotification');
App::import('Vendor', 'gcheckout/googlenotificationhistory');
App::import('Vendor', 'gcheckout/googlepoll');
App::import('Vendor', 'gcheckout/googlerequest');
App::import('Vendor', 'gcheckout/googleresponse');
App::import('Vendor', 'gcheckout/googleresult');
App::import('Vendor', 'gcheckout/googleshipping');
App::import('Vendor', 'gcheckout/googlesubscription');
App::import('Vendor', 'gcheckout/googletax');
App::import('Vendor', 'gcheckout/htmlSignatureGen');
define('RESPONSE_HANDLER_ERROR_LOG_FILE', 'googleerror.log');
define('RESPONSE_HANDLER_LOG_FILE', 'googlemessage.log');

class GoogleCheckoutComponent extends Object {

    var $components = array('Session');
    var $_merchantID;
    var $_merchantKey;
    //1 == log to errorlog only, 2 == log to browser only, 3 == log to browser & error log
    var $_loggingLevel = 3;
    var $_curreny;
    var $_testing;
    var $_approotdir = APP_DIR;
    var $_items = array();
    var $_gserve;
    var $_cartId;
    var $_paymentType;
    var $_continueShopping;
    /*
     * 
     */

    function startup(&$controller) {
        $this->_Paymentmethod = ClassRegistry::init('Paymentmethod');
        $this->_invoice = ClassRegistry::init('Invoice');
        $this->_Order = ClassRegistry::init('Order');
        $this->_Cart = ClassRegistry::init('Cart');
        $this->_Product = ClassRegistry::init('Product');
        $paymentsGateway = $this->_Paymentmethod->find("first", array("conditions" => array("Paymentmethod.user_id" => $this->Session->read('payToId'), "Paymentmethod.methodname" => "Google Checkout")));
        $this->_merchantID = $paymentsGateway['Paymentmethod']['apiuser'];
        $this->_merchantKey = $paymentsGateway['Paymentmethod']['apisigniture'];
        $this->_currency = (isset($controller->currency)) ? $controller->currency : 'USD';
        $this->_continueShopping = 'http://stage.authenticavenue.com/';
        if (isset($controller->editcartlink))
            $this->_editcartlink = $controller->editcartlink;

        //$this->_restoreFromSessionArr();
        if ($paymentsGateway['Paymentmethod']['state'] == "live")
            $this->_gserve = 'Production';
        else
            $this->_gserve = 'sandbox';
    }

    function setItem($title, $desc, $count, $price, $merchantItemID=null, $data=null) {

        if ($data) {
            $this->_items[] = array('title' => $title, 'desc' => $desc, 'count' => $count, 'price' => $price, 'data' => $data);
        } else {
            $this->_items[] = array('title' => $title, 'desc' => $desc, 'count' => $count, 'price' => $price);
        }

        return true;
    }

    /*
     * 
     */

    function dumpToSessionArr() {
        if (!empty($this->_items)) {
            $sessR = array($this->_items);
            return $this->Session->write('Google', $sessR);
        }
    }

    /*
     * 
     */

    function _restoreFromSessionArr() {
        $sessR = $this->Session->read('Google');
        if ($sessR == false) {
            return false;
        } else {
            $this->_items = $sessR;
            return true;
        }
    }

    /*
     * 
     */

    function getCartItems() {
        return $this->_items;
    }

    /*
     * 
     */

    function getCartPreTaxTotal() {
        $total = 0;

        foreach ($this->_items as $item) {
            $total += $item['price'];
        }

        return $total;
    }

    /*
     * 
     */

    function generateCartButton($data=null, $theitems=array()) {
        $cart = new GoogleCart($this->_merchantID, $this->_merchantKey, $this->_gserve, $this->_currency);
        $counter = 1;
        if (!empty($theitems)) {
            $thisitems = $theitems;
        } else {
            $thisitems = $this->_items;
        }

        //$thisitems=array();
        foreach ($thisitems as $item) {
            $varvar = 'item_' . $counter;
            ${$varvar} = new GoogleItem($item['title'], // Item name
                            $item['desc'], // Item description
                            $item['count'], // Quantity
                            $item['price'] // Unit price
            );
            if (isset($item['data'])) {
                ${$varvar}->SetMerchantPrivateItemData(new MerchantPrivateItemData($item['data']));
            }
            if (isset($item['id'])) {
                ${$varvar}->SetMerchantItemId($item['id']);
            }
            $cart->AddItem(${$varvar});
        }
        // Set the acct. name, etc.
        if ($data)
            $cart->SetMerchantPrivateData(new MerchantPrivateData($data));

        // Specify "Return to xyz" link
        $cart->SetContinueShoppingUrl($this->_continueShopping);
        if (isset($this->_editcartlink))
            $cart->SetEditCartUrl($this->_editcartlink);

        // Display Google Checkout button
        return $cart->CheckoutButtonCode("SMALL");
    }

    /*
     * 	Destruct only automatically saves the cart to the User�s session in php5
     */

    function __destruct() {
        $this->dumpToSessionArr();
    }

    /*
     * 
     */

    function ProcessXmlData($xml_data) {
        $dom_response_obj = domxml_open_mem($xml_data);
        $dom_data_root = $dom_response_obj->document_element();
        $message_recognizer = $dom_data_root->tagname();
        /*
          //requests, errors and problem solving
         *     <request-received>
         *     <error>
         *     <diagnosis>
          //Go to google and pay for it.
         *     <checkout-redirect> //a redirect
          //Notifications....
         *     <merchant-calculation-callback>
         *     <new-order-notification>
         *     <order-state-change-notification>
         *     <charge-amount-notification>
         *     <chargeback-amount-notification>
         *     <refund-amount-notification>
         *     <risk-information-notification>
         */
        switch ($message_recognizer) {
            // <checkout-redirect> received //handled in a predictable manner, so I can integrate this one...
            case "checkout-redirect":
                $this->_ProcessCheckoutRedirect($dom_response_obj);
                break;
            case "request-received":
            case "error":
            case "diagnosis":
            case "merchant-calculation-callback":
                return array($message_recognizer, $dom_response_obj);
                break;
            case "new-order-notification":
            case "order-state-change-notification":
            case "charge-amount-notification":
            case "chargeback-amount-notification":
            case "refund-amount-notification":
            case "risk-information-notification":
                return array($message_recognizer, $dom_response_obj);
                break;
            default:
                $this->log("GCheckoutComponent: Response '$message_recognizer' unknown.");
                break;
        }
    }

    function _ProcessCheckoutRedirect($dom_response_obj) {
        // Identify the URL to which the customer should be redirected
        $dom_data_root = $dom_response_obj->document_element();
        $redirect_url_list = $dom_data_root->get_elements_by_tagname("redirect-url");
        $redirect_url = $redirect_url_list[0]->get_content();
        // Redirect the customer to the URL
        $this->controller->redirect($redirect_url);
        exit();
    }

    function _SendNotificationAcknowledgment() {
        $acknowledgement = "<notification-acknowledgment xmlns=\"" . $GLOBALS["schema_url"] . "\"/>";
        return $acknowledgment;

        // Log <notification-acknowledgment> was at least called from cake controller
        LogMessage($GLOBALS["logfile"], $acknowledgment);
    }

    /**
     * The CreateArchiveOrder function is a wrapper function that calls the
     * ChangeOrderState function. The ChangeOrderState function, in turn,
     * creates an <archive-order> command for the specified order, which is
     * identified by its Google Checkout order number ($google_order_number). The 
     * <archive-order> command moves an order from the Inbox in the Google Checkout
     * Merchant Center to the Archive folder.
     *
     * @param   $google_order_number    A number, assigned by Google Checkout, 
     *                                      that uniquely identifies an order.
     * @return  <archive-order> XML
     */
    function CreateArchiveOrder($google_order_number) {
        return ChangeOrderState($google_order_number, "archive");
    }

    /**
     * The CreateCancelOrder function is a wrapper function that calls the
     * ChangeOrderState function. The ChangeOrderState function, in turn,
     * creates a <cancel-order> command for the specified order, which is
     * identified by its Google Checkout order number ($google_order_number). The 
     * <cancel-order> command instructs Google Checkout to cancel an order.
     *
     * @param   $google_order_number    A number, assigned by Google Checkout, 
     *                                      that uniquely identifies an order.
     * @param   $reason                 The reason an order is being canceled
     * @param   $comment                A comment pertaining to a canceled order
     * @return  <cancel-order> XML
     */
    function CreateCancelOrder($google_order_number, $reason, $comment="") {
        return ChangeOrderState($google_order_number, "cancel", $reason, 0, $comment);
    }

    /**
     * The CreateChargeOrder function is a wrapper function that calls the
     * ChangeOrderState function. The ChangeOrderState function, in turn,
     * creates a <charge-order> command for the specified order, which is
     * identified by its Google Checkout order number ($google_order_number). The
     * <charge-order> command prompts Google Checkout to charge the customer for an 
     * order and to change the order's financial order state to "CHARGING".
     *
     * @param   $google_order_number    A number, assigned by Google Checkout, 
     *                                      that uniquely identifies an order.
     * @param   $amount                 The amount that Google Checkout should 
     *                                      charge the customer
     * @return  <charge-order> XML
     */
    function CreateChargeOrder($google_order_number, $amount="") {
        return ChangeOrderState($google_order_number, "charge", 0, $amount);
    }

    /**
     * The CreateProcessOrder function is a wrapper function that calls the
     * ChangeOrderState function. The ChangeOrderState function, in turn,
     * creates a <process-order> command for the specified order, which is
     * identified by its Google Checkout order number ($google_order_number). The
     * <process-order> command changes the order's fulfillment order state 
     * to "PROCESSING".
     *
     * @param   $google_order_number    A number, assigned by Google Checkout, 
     *                                      that uniquely identifies an order.
     * @return  <process-order> XML
     */
    function CreateProcessOrder($google_order_number) {
        return ChangeOrderState($google_order_number, "process");
    }

    /**
     * The CreateRefundOrder function is a wrapper function that calls the
     * ChangeOrderState function. The ChangeOrderState function, in turn,
     * creates a <refund-order> command for the specified order, which is
     * identified by its Google Checkout order number ($google_order_number). The 
     * <refund-order> command instructs Google Checkout to issue a refund for an 
     * order.
     *
     * @param   $google_order_number    A number, assigned by Google Checkout, 
     *                                      that uniquely identifies an order.
     * @param   $reason                 The reason an order is being refunded
     * @param   $amount                 The amount that Google Checkout should 
     *                                      refund to the customer.
     * @param   $comment                A comment pertaining to a refunded order
     * @return  <refund-order> XML
     */
    function CreateRefundOrder($google_order_number, $reason, $amount="", $comment="") {

        return ChangeOrderState($google_order_number, "refund", $reason, $amount, $comment);
    }

    /**
     * The CreateUnarchiveOrder function is a wrapper function that calls the
     * ChangeOrderState function. The ChangeOrderState function, in turn,
     * creates an <unarchive-order> command for the specified order, which is
     * identified by its Google Checkout order number ($google_order_number). The 
     * <unarchive-order> command moves an order from the Archive folder in the
     * Google Checkout Merchant Center to the Inbox.
     *
     * @param   $google_order_number    A number, assigned by Google Checkout, 
     *                                      that uniquely identifies an order.
     * @return  <unarchive-order> XML
     */
    function CreateUnarchiveOrder($google_order_number) {
        return ChangeOrderState($google_order_number, "unarchive");
    }

    function process_response() {
        $Gresponse = new GoogleResponse($this->_merchantID, $this->_merchantKey);
        $Grequest = new GoogleRequest($this->_merchantID, $this->_merchantKey, $this->_gserve, $this->_currency);

        //Setup the log file
        $Gresponse->SetLogFiles(RESPONSE_HANDLER_ERROR_LOG_FILE, RESPONSE_HANDLER_LOG_FILE, L_ALL);

        //Retrieve the XML sent in the HTTP POST request to the ResponseHandler
        $xml_response = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : file_get_contents("php://input");
        if (get_magic_quotes_gpc()) {
            $xml_response = stripslashes($xml_response);
        }
        list($root, $data) = $Gresponse->GetParsedXML($xml_response);
        $Gresponse->SetMerchantAuthentication($this->_merchantID, $this->_merchantKey);

        /* $status = $Gresponse->HttpAuthentication();
          if(! $status) {
          die('authentication failed');
          } */

        /* Commands to send the various order processing APIs
         * Send charge order : $Grequest->SendChargeOrder($data[$root]
         *    ['google-order-number']['VALUE'], <amount>);
         * Send process order : $Grequest->SendProcessOrder($data[$root]
         *    ['google-order-number']['VALUE']);
         * Send deliver order: $Grequest->SendDeliverOrder($data[$root]
         *    ['google-order-number']['VALUE'], <carrier>, <tracking-number>,
         *    <send_mail>);
         * Send archive order: $Grequest->SendArchiveOrder($data[$root]
         *    ['google-order-number']['VALUE']);
         *
         */

        switch ($root) {
            case "request-received": {
                    break;
                }
            case "error": {
                    break;
                }
            case "diagnosis": {
                    break;
                }
            case "checkout-redirect": {
                    break;
                }
            case "merchant-calculation-callback": {
                    // Create the results and send it
                    $merchant_calc = new GoogleMerchantCalculations($currency);

                    // Loop through the list of address ids from the callback
                    $addresses = $this->get_arr_result($data[$root]['calculate']['addresses']['anonymous-address']);
                    foreach ($addresses as $curr_address) {
                        $curr_id = $curr_address['id'];
                        $country = $curr_address['country-code']['VALUE'];
                        $city = $curr_address['city']['VALUE'];
                        $region = $curr_address['region']['VALUE'];
                        $postal_code = $curr_address['postal-code']['VALUE'];

                        // Loop through each shipping method if merchant-calculated shipping
                        // support is to be provided
                        if (isset($data[$root]['calculate']['shipping'])) {
                            $shipping = $this->get_arr_result($data[$root]['calculate']['shipping']['method']);
                            foreach ($shipping as $curr_ship) {
                                $name = $curr_ship['name'];
                                //Compute the price for this shipping method and address id
                                $price = 12; // Modify this to get the actual price
                                $shippable = "true"; // Modify this as required
                                $merchant_result = new GoogleResult($curr_id);
                                $merchant_result->SetShippingDetails($name, $price, $shippable);

                                if ($data[$root]['calculate']['tax']['VALUE'] == "true") {
                                    //Compute tax for this address id and shipping type
                                    $amount = 15; // Modify this to the actual tax value
                                    $merchant_result->SetTaxDetails($amount);
                                }

                                if (isset($data[$root]['calculate']['merchant-code-strings']
                                                ['merchant-code-string'])) {
                                    $codes = $this->get_arr_result($data[$root]['calculate']['merchant-code-strings']
                                            ['merchant-code-string']);
                                    foreach ($codes as $curr_code) {
                                        //Update this data as required to set whether the coupon is valid, the code and the amount
                                        $coupons = new GoogleGiftcerts("true", $curr_code['code'], 10, "debugtest");
                                        $merchant_result->AddGiftCertificates($coupons);
                                    }
                                }
                                $merchant_calc->AddResult($merchant_result);
                            }
                        } else {
                            $merchant_result = new GoogleResult($curr_id);
                            if ($data[$root]['calculate']['tax']['VALUE'] == "true") {
                                //Compute tax for this address id and shipping type
                                $amount = 15; // Modify this to the actual tax value
                                $merchant_result->SetTaxDetails($amount);
                            }
                            $codes = $this->get_arr_result($data[$root]['calculate']['merchant-code-strings']
                                    ['merchant-code-string']);
                            foreach ($codes as $curr_code) {
                                //Update this data as required to set whether the coupon is valid, the code and the amount
                                $coupons = new GoogleGiftcerts("true", $curr_code['code'], 10, "debugtest");
                                $merchant_result->AddGiftCertificates($coupons);
                            }
                            $merchant_calc->AddResult($merchant_result);
                        }
                    }
                    $Gresponse->ProcessMerchantCalculations($merchant_calc);
                    break;
                }
            case"new-order-notification": {
                    $cartId = $data[$root]['shopping-cart']['merchant-private-data']['cart-id']['VALUE'];
                    $paymentType = $data[$root]['shopping-cart']['merchant-private-data']['paymentType']['VALUE'];
                    $transactionId = $data[$root]['google-order-number']['VALUE'];
                    $this->CreateOrder($cartId, $transactionId, $paymentType);
                    $Gresponse->SendAck();
                    break;
                }
            case"order-state-change-notification": {
                    $new_financial_state = $data[$root]['new-financial-order-state']['VALUE'];
                    $new_fulfillment_order = $data[$root]['new-fulfillment-order-state']['VALUE'];

                    switch ($new_financial_state) {
                        case 'REVIEWING': {
                                break;
                            }
                        case 'CHARGEABLE': {
                                //$Grequest->SendProcessOrder($data[$root]['google-order-number']['VALUE']);
                                //$Grequest->SendChargeOrder($data[$root]['google-order-number']['VALUE'],'');
                                break;
                            }
                        case 'CHARGING': {
                                break;
                            }
                        case 'CHARGED': {
                                //if($data[$root]['shopping-cart']['merchant-private-data']['paymentType']['VALUE']=="invoice"){
                                $this->updateInvoice($data[$root]['google-order-number']['VALUE']);
                                //}
                                break;
                            }
                        case 'PAYMENT_DECLINED': {
                                break;
                            }
                        case 'CANCELLED': {
                                break;
                            }
                        case 'CANCELLED_BY_GOOGLE': {
                                //$Grequest->SendBuyerMessage($data[$root]['google-order-number']['VALUE'],
                                //    "Sorry, your order is cancelled by Google", true);
                                break;
                            }
                        default:
                            break;
                    }

                    switch ($new_fulfillment_order) {
                        case 'NEW': {
                                break;
                            }
                        case 'PROCESSING': {
                                break;
                            }
                        case 'DELIVERED': {
                                $this->updateShipping($data[$root]['google-order-number']['VALUE']);
                                break;
                            }
                        case 'WILL_NOT_DELIVER': {
                                break;
                            }
                        default:
                            break;
                    }
                    $Gresponse->SendAck();
                    break;
                }
            case "charge-amount-notification": {
                    //$Grequest->SendDeliverOrder($data[$root]['google-order-number']['VALUE'],
                    //    <carrier>, <tracking-number>, <send-email>);
                    //$Grequest->SendArchiveOrder($data[$root]['google-order-number']['VALUE'] );
                    $Gresponse->SendAck();
                    break;
                }
            case "chargeback-amount-notification": {
                    $Gresponse->SendAck();
                    break;
                }
            case "refund-amount-notification": {
                    $Gresponse->SendAck();
                    break;
                }
            case "risk-information-notification": {
                    $Gresponse->SendAck();
                    break;
                }
            default:
                $Gresponse->SendBadRequestStatus("Invalid or not supported Message");
                break;
        }
    }

    /* In case the XML API contains multiple open tags
      with the same value, then invoke this function and
      perform a foreach on the resultant array.
      This takes care of cases when there is only one unique tag
      or multiple tags.
      Examples of this are "anonymous-address", "merchant-code-string"
      from the merchant-calculations-callback API
     */

    function get_arr_result($child_node) {
        $result = array();
        if (isset($child_node)) {
            if ($this->is_associative_array($child_node)) {
                $result[] = $child_node;
            } else {
                foreach ($child_node as $curr_node) {
                    $result[] = $curr_node;
                }
            }
        }
        return $result;
    }

    /* Returns true if a given variable represents an associative array */

    function is_associative_array($var) {
        return is_array($var) && !is_numeric(implode('', array_keys($var)));
    }

    function CreateOrder($cartIds, $transactionId, $paymentType) {
        if ($paymentType == "invoice") {
            $datas['Invoice']['id'] = $cartIds;
            $datas['Invoice']['sahbaj'] = $cartIds . "=>" . $transactionId . "->" . $paymentType;
            $datas['Invoice']['transaction_id'] = $transactionId;
            $this->_invoice->save($datas['Invoice']);
            //$this->SendGoogleNewOrderId($transactionId, $cartId);
        } else {
            /* $Cart['id']=$cartId;
              $Cart['status']=1;
              $Cart['payment_status']=1;
              $this->_Cart->save($Cart);
              $cart=$this->_Cart->find("first",array("conditions"=>array("Cart.id"=>$cartId)));

              $this->_Product->query("UPDATE authentic_products SET product_totalsell=product_totalsell+".$cart['Cart']['quantity']." WHERE id='".$cart['Cart']['product_id']."'");
              $Order['user_id']=$cart['Cart']['user_id'];
              $Order['cart_id']=$cart['Cart']['id'];
              $Order['product_id']=$cart['Cart']['product_id'];
              $Order['quantity']=$cart['Cart']['quantity'];
              $Order['product_cost']=$cart['Cart']['product_cost'];
              $Order['shipping_cost']='0.00';
              $Order['transaction_id']=$transactionId;
              $this->_Order->save($Order);
             */
            $product_cost = 0;
            $cart_ids = explode("|", $cartIds);
            foreach ($cart_ids as $cart_id) {
                $Cart['id'] = $cart_id;
                $Cart['status'] = 1;
                $Cart['payment_status'] = 1;
                $this->Cart->save($Cart);
                $cart = $this->_Cart->find("first", array("conditions" => array("Cart.id" => $Cart['id'])));
                $seller_id = $carts['Cart']['seller_id'];
                $product_cost = $product_cost + $cart['Cart']['product_cost'];
                $this->_Product->query("UPDATE authentic_products SET product_totalsell=product_totalsell+" . $cart['Cart']['quantity'] . " WHERE id='" . $cart['Cart']['product_id'] . "'");
            }

            $Order['shipping_cost'] = $cart['Cart']['shipping_cost'];
            $Order['payment_status'] = "Pending";
            $Order['transaction_id'] = $transactionId;
            $Order['seller_id'] = $seller_id;
            $Order['add_date'] = date("Y-m-d H:i:s");
            $Order['product_cost'] = $product_cost;
            $this->_Order->save($Order);
            $order_id = $this->_Order->getlastinsertid();
            foreach ($cart_ids as $cart_id) {
                $Cart['id'] = $cart_id;
                $Cart['order_id'] = $order_id;
                $this->_Cart->save($Cart);
            }
        }
    }

    function updateInvoice($transactionId) {
        $cart_id = $this->_invoice->find("first", array("conditions" => array("Invoice.transaction_id" => $transactionId), "fields" => array('Invoice.id')));
        if (isset($cart_id['Invoice']['id'])) {
            $datas['Invoice']['id'] = $cart_id['Invoice']['id'];
            $datas['Invoice']['sahbaj'] = $transactionId . "<=" . $cart_id['Invoice']['id'];
            $datas['Invoice']['invoice_status'] = "Paid Invoices";
            $datas['Invoice']['pay_date'] = date("Y-m-d H:i:s");
            $this->_invoice->save($datas['Invoice']);
        } else {
            $order = $this->_Order->find("first", array("conditions" => array("Order.transaction_id" => $transactionId), "fields" => array('Order.id')));
            $Order['id'] = $order['Order']['id'];
            $Order['payment_status'] = "Complete";
            $Order['add_date'] = date("Y-m-d H:i:s");
            $this->_Order->save($Order);
        }
    }

    function updateShipping($transactionId) {
        $order = $this->_Order->find("first", array("conditions" => array("Order.transaction_id" => $transactionId), "fields" => array('Order.id')));
        $Order['id'] = $order['Order']['id'];
        $Order['shipping_status'] = "Complete";
        $this->_Order->save($Order);
    }

    function SendGoogleNewOrderId($googleid, $orderid) {
        $Grequest = new GoogleRequest($this->_merchantID, $this->_merchantKey, $this->_gserve, $this->_currency);
        $request_result = $Grequest->SendMerchantOrderNumber($googleid, $orderid);
    }

}

?>